package com.jiang.demo.dao.jpa.handler;

import cn.hutool.core.bean.BeanUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.jiang.demo.common.util.JsonUtil;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.DynamicParameterizedType;
import org.hibernate.usertype.UserType;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import java.util.Objects;
import java.util.Properties;

/**
 * =====================================================================================================================
 * jiangshaoneng <15673219519.@163.com> 2022/11/1 14:25
 * =====================================================================================================================
 */
public class LongListType implements UserType, DynamicParameterizedType {

    private Class<?> objectClass;
    private static final int[] SQL_TYPES = new int[] { Types.LONGVARCHAR };

    @Override
    public void setParameterValues(Properties parameters) {
        final ParameterType reader = (ParameterType) parameters.get(PARAMETER_TYPE);
        if (reader != null) {
            objectClass = reader.getReturnedClass();
        }
    }

    @Override
    public int[] sqlTypes() {
        return SQL_TYPES;
    }

    @Override
    public Class<?> returnedClass() {
        return objectClass;
    }

    /**
     * 是否相等，不相等会触发JPA update操作
     *
     * @param x
     * @param y
     * @throws HibernateException
     */
    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return Objects.equals(x, y);
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        return x == null ? 0 : x.hashCode();
    }

    /**
     * 返回对象值
     *
     * @param rs
     * @param names
     * @param session
     * @param owner
     * @throws HibernateException
     * @throws SQLException
     */
    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
            throws HibernateException, SQLException {
        String value = rs.getString(names[0]);
        if (BeanUtil.isEmpty(value)) {
            return null;
        }
        try {
            return JsonUtil.json2Object(value, new TypeReference<List<Long>>() {
            });
        } catch (Exception e) {
            throw new RuntimeException(String.format("Unknown value [%s] for [%s]", value, objectClass.getName()));
        }
    }

    /**
     * 保存对象值
     *
     * @param st
     * @param value
     * @param index
     * @param session
     * @throws HibernateException
     * @throws SQLException
     */
    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
            throws HibernateException, SQLException {
        if (value == null) {
            st.setNull(index, SQL_TYPES[0]);
        } else {
            try {
                st.setObject(index, JsonUtil.object2Json(value));
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        }
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return cached;
    }

    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }

}